home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / fscheck / fscheck.c.bad < prev    next >
Encoding:
Text File  |  1990-11-02  |  50.1 KB  |  1,407 lines

  1. /* 
  2.  * fscheck.c --
  3.  *
  4.  *    Perform consistency checks on a filesystem.
  5.   *
  6.  * Copyright 1989 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/cmds/fscheck/RCS/fscheck.c,v 1.37 90/11/01 23:27:34 jhh Exp $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20. #include "option.h"
  21. #include "list.h"
  22. #include "fscheck.h"
  23. #include <string.h>
  24. #include <host.h>
  25. #include <sys/file.h>
  26. #include <sys/stat.h>
  27. #include <stdio.h>
  28.  
  29. int    numBlocks = 0;
  30. int    numFiles = 0;
  31. int    numBadDesc = 0;
  32. int    numFrags = 0;
  33. int    errorType = EXIT_OK;
  34. int    foundError = 0;
  35. int    fdBitmapError = 0;
  36. Boolean    tooBig = FALSE;
  37. Ofs_DomainHeader  *domainPtr;
  38. int        partFID;
  39. Boolean patchHeader = FALSE;
  40. Boolean    attached    = FALSE;
  41.  
  42. /*
  43.  * The following are used to go from a command line like
  44.  * fscheck -dev rsd0 -part b
  45.  * to /dev/rsd0a     - for the partition that has the disk label
  46.  * and to /dev/rsd0b    - for the partition to format.
  47.  */
  48. char *deviceName;        /* Set to "rsd0" or "rxy1", etc. */
  49. char *partName;            /* Set to "a", "b", "c" ... "g" */
  50. char defaultFirstPartName[] = "a";
  51. char *firstPartName = defaultFirstPartName;
  52. char defaultDevDirectory[] = "/dev/";
  53. char *devDirectory = defaultDevDirectory;
  54. char *outputFileName = NULL;
  55.  
  56. int hostID = -1;
  57. int writeDisk = 0;
  58. int verbose = 0;
  59. int silent = 0;
  60. int clearDomainNumber = 0;
  61. int recoveryCheck = 0;
  62. int badBlockInit = 0;
  63. int patchRoot = 0;
  64. int rawOutput = FALSE;
  65. int maxHeapSize = -1;
  66. int bufferSize = BUFSIZ;
  67. int heapSize = 0;
  68. int noCopy = FALSE;
  69. int blocksToRead = 1;
  70. int debug = FALSE;
  71. int clearFixCount = FALSE;
  72. int bitmapVerbose = 0;
  73. int numReboot = 4;
  74. int blockToFind = -1;
  75. int fileToPrint = -1;
  76. int dontRecheck = 0;
  77. int setCheckedBit = FALSE;
  78.  
  79. Option optionArray[] = {
  80.     {OPT_STRING, "dev", (Address)&deviceName,
  81.     "Required: Name of device, eg \"rsd0\" or \"rxy1\""},
  82.     {OPT_STRING, "part", (Address)&partName,
  83.     "Required: Partition ID: (a, b, c, d, e, f, g)"},
  84.     {OPT_STRING, "dir", (Address)&devDirectory,
  85.     "Name of device directory (\"/dev/\")"},
  86.     {OPT_STRING, "initialPart", (Address)&firstPartName,
  87.     "Name of initial partition (\"a\")"},
  88.     {OPT_TRUE, "write", (Address)&writeDisk,
  89.     "Write disk "},
  90.     {OPT_TRUE, "silent", (Address)&silent,
  91.     "Don't say anything unless there's a problem "},
  92.     {OPT_TRUE, "verbose", (Address)&verbose,
  93.     "Output information about differences in bitmaps "},
  94.     {OPT_TRUE, "fixRoot", (Address)&patchRoot,
  95.      "Re-create the missing/corrupt root directory."},
  96.     {OPT_TRUE, "clear", (Address)&clearDomainNumber,
  97.     "Clear the domain number field stored in the summary sector"},
  98.     {OPT_INT, "hostID", (Address)&hostID,
  99.     "Update the host ID in the disk header"},
  100.     {OPT_TRUE, "badBlock", (Address)&badBlockInit,
  101.     "Initialize the bad block file descriptor"},
  102.     {OPT_STRING, "outputFile", (Address)&outputFileName,
  103.     "Name of file in which to store output."},    
  104.     {OPT_TRUE, "rawOutput", (Address) &rawOutput,
  105.     "Bypass the filesystem when writing the output into the file."},
  106.     {OPT_INT, "heapLimit", (Address)&maxHeapSize,
  107.     "Maximum amount of dynamic storage allowed."},
  108.     {OPT_INT, "bufferSize", (Address)&bufferSize,
  109.     "Size of buffer for output file stream."},
  110.     {OPT_TRUE, "delete", (Address)&noCopy,
  111.     "Truncate files containing duplicate blocks."},
  112.     {OPT_TRUE, "debug", (Address)&debug,
  113.     "Print debugging information."},
  114.     {OPT_INT, "readBlock", (Address)&blocksToRead,
  115.     "Number of blocks to read at a time."},
  116.     {OPT_TRUE, "clearFixCount", (Address)&clearFixCount,
  117.     "Clear the count of consecutive disk fixes in summary sector"},
  118.     {OPT_TRUE, "bitmapVerbose", (Address)&bitmapVerbose,
  119.     "Print information about bitmap errors."},
  120.     {OPT_INT, "numReboot", (Address)&numReboot,
  121.     "Number of consecutive runs before returning EXIT_NOREBOOT"},
  122.     {OPT_INT, "block", (Address)&blockToFind,
  123.     "Block to look for"},
  124.     {OPT_INT, "file", (Address)&fileToPrint,
  125.     "File to print"},
  126.     {OPT_TRUE, "cond", (Address)&dontRecheck,
  127.     "Don't check the disk if it has just been checked successfully"},
  128.     {OPT_TRUE, "setCheck", (Address)&setCheckedBit,
  129.     "If the disk is checked and fixed ok set a bit in the summary sector"},
  130. };
  131. int numOptions = sizeof(optionArray) / sizeof(Option);
  132.  
  133. /*
  134.  * Forward Declarations.
  135.  */
  136. void        CheckFilesystem();
  137. int        RecoveryCheck();
  138.  
  139. /*
  140.  * The last file that an error message was printed about.
  141.  */
  142. int        lastErrorFD = -1;
  143. int        fixCount = 0;
  144.  
  145.  
  146. /*
  147.  *----------------------------------------------------------------------
  148.  *
  149.  * main --
  150.  *
  151.  *    Create the required file names from the command line
  152.  *    arguments.  Then open the first partition on the disk
  153.  *    because it contains the disk label, and open the partition
  154.  *    that is to be checked.
  155.  *
  156.  * Results:
  157.  *
  158.  * Side effects:
  159.  *    File opening.
  160.  *
  161.  *----------------------------------------------------------------------
  162.  */
  163. main(argc, argv)
  164.     int argc;
  165.     char *argv[];
  166. {
  167.     int        firstPartFID;
  168.     char    firstPartitionName[64];
  169.     char    partitionName[64];
  170.     int        partition;
  171.     u_char      *streamBuffer;
  172.     int        outputFID;
  173.     char    *timeString;
  174.     struct timeval tp;
  175.     struct timezone tzp;
  176.     int        argsReturned;
  177.  
  178.  
  179.     argsReturned = Opt_Parse(argc, argv, optionArray, numOptions, 0);
  180.     if (argsReturned > 1) {
  181.     Opt_PrintUsage(argv[0], optionArray, Opt_Number(optionArray));
  182.     exit(EXIT_BAD_ARG);
  183.     }
  184.     /*
  185.      * Set up stream for output to file, as well as output to stderr.
  186.      */
  187.     if (outputFileName == NULL) {
  188.     outputFile = NULL;
  189.     } else if (!rawOutput) {
  190.     outputFile = fopen(outputFileName,"a+");
  191.     if (outputFile == NULL ) {
  192.         OutputPerror("fscheck: Can't open output file \"%s\\n", 
  193.         outputFileName);
  194.         exit(EXIT_HARD_ERROR);
  195.     }
  196.     if (bufferSize != BUFSIZ) {
  197.         if (setvbuf(outputFile,(char *) NULL,_IOFBF,bufferSize)) {
  198.         Output(stderr,
  199.                "fscheck: Unable to change output buffer size.\n");
  200.         if (maxHeapSize > 0) {
  201.             maxHeapSize -= bufferSize;
  202.         }
  203.         }
  204.     }
  205.     } else {
  206.     if (bufferSize > FSDM_NUM_DIRECT_BLOCKS * FS_BLOCK_SIZE) {
  207.         Output(stderr,
  208. "Maximum buffer size allowed when using raw output is %d bytes.\n",
  209.         FSDM_NUM_DIRECT_BLOCKS * FS_BLOCK_SIZE);
  210.         exit(EXIT_BAD_ARG);
  211.     }
  212.     Alloc(streamBuffer,u_char,bufferSize);
  213.         Stdio_Setup(outputFile,0,1,streamBuffer,bufferSize,NULL,
  214.         WriteOutputFile, CloseOutputFile,NULL);
  215.     }
  216.     if (rawOutput) {
  217.     Output(stderr,"      \n");
  218.     }
  219.     gettimeofday(&tp,&tzp);
  220.     timeString = asctime(localtime(&tp.tv_sec));
  221.     if (verbose) {
  222.     Output(stderr,"***** Fscheck *****\n");
  223.     }
  224.     if (!silent) {
  225.     Output(stderr,"%s",timeString);
  226.     }
  227.     if (tooBig) {
  228.     Output(stderr,"fscheck: Heap limit too small.\n");
  229.     exit(EXIT_MORE_MEMORY);
  230.     }
  231.     if (deviceName == (char *)0) {
  232.     Output(stderr, "Specify device name with -dev option\n");
  233.     exit(EXIT_BAD_ARG);
  234.     }
  235.     if (partName == (char *)0) {
  236.     Output(stderr, "Specify partition with -part option\n");
  237.     exit(EXIT_BAD_ARG);
  238.     }
  239.     if (blocksToRead <= 0) {
  240.     Output(stderr,"blocksToRead value %d illegal - using 1.\n");
  241.     blocksToRead = 1;
  242.     }
  243.     if (patchRoot && !writeDisk) {
  244.     Output(stderr, 
  245.          "Sorry but you can't patch the root without writing the disk.\n");
  246.         exit(EXIT_BAD_ARG);
  247.     }
  248.     if (hostID != -1) {
  249.     patchHeader = TRUE;
  250.     }
  251.     /*
  252.      * Gen up the name of the first partition on the disk,
  253.      * and the name of the partition that needs to be checked.
  254.      */
  255.     (void)strcpy(firstPartitionName, devDirectory);  /* eg. /dev/ */
  256.     (void)strcpy(partitionName, devDirectory);    
  257.     (void)strcat(firstPartitionName, deviceName);      /* eg. /dev/rxy0 */
  258.     (void)strcat(partitionName, deviceName);    
  259.     (void)strcat(firstPartitionName, firstPartName);  /* eg. /dev/rxy0a */
  260.     (void)strcat(partitionName, partName);          /* eg. /dev/rxy0b */
  261.  
  262.     firstPartFID = open(firstPartitionName, O_RDONLY);
  263.     if (firstPartFID < 0) {
  264.     OutputPerror("fscheck: Can't open first partition");
  265.     exit(EXIT_HARD_ERROR);
  266.     }
  267.     partFID = open(partitionName, writeDisk ? O_RDWR : O_RDONLY);
  268.     if (partFID < 0) {
  269.     OutputPerror("fscheck: Can't open partition to check ");
  270.     exit(EXIT_HARD_ERROR);
  271.     }
  272.  
  273.     partition = partName[0] - 'a';
  274.     if (partition < 0 || partition > 7) {
  275.     Output(stderr,
  276.          "fscheck: Can't determine partition index from the partition name\n");
  277.     exit(EXIT_BAD_ARG);
  278.     }
  279.     if ((maxHeapSize > 0) && (bufferSize >= maxHeapSize)) {
  280.     Output(stderr,
  281.            "fscheck: Size of output buffer exceeds maximum heap size.\n");
  282.     exit(EXIT_MORE_MEMORY);
  283.     }
  284.     CheckFilesystem(firstPartFID, partFID, partition);
  285.  
  286.     if (outputFile != NULL) {
  287.     (void)fclose(outputFile);
  288.     }
  289.     (void)close(firstPartFID);
  290.     (void)close(partFID);
  291.     if (foundError) {
  292.     if (attached) {
  293.         exit(EXIT_REBOOT);
  294.     }
  295.     if (errorType != EXIT_OK) {
  296.         exit(errorType);
  297.     }
  298.     exit(EXIT_SOFT_ERROR);
  299.     }
  300.     exit(EXIT_OK);
  301. }
  302.  
  303. unsigned char *fdBitmapPtr;
  304. unsigned char *cylBitmapPtr;
  305.  
  306. /*
  307.  * Array to provide the ability to set and extract bits out of a bitmap byte.
  308.  */
  309. unsigned char bitmasks[BITS_PER_BYTE] = {
  310.     0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1
  311. };
  312.  
  313. void         ReadDomainHeader();
  314. void        CheckDirTree();
  315. void        CheckBlocks();
  316. unsigned char     *ReadFileDescBitmap();
  317. unsigned char     *ReadBitmap();
  318. FdInfo        *ReadFileDesc();
  319. void        WriteDomainHeader();
  320. void        WriteFileDescBitmap();
  321. void        WriteBitmap();
  322. void        WriteFileDesc();
  323. void        WriteSummaryInfo();
  324. void        CheckFDBitmap();
  325. void        SetBadDescBitmap();
  326. void        RelocateFD();
  327.  
  328. int    num1KBlocks;
  329. int    bytesPerCylinder;
  330.  
  331. List_Links    copyListHdr;
  332. List_Links    relocListHdr;
  333. List_Links    modListHdr;
  334. #define tempCopyList &tempCopyListHdr;
  335.  
  336.  
  337. /*
  338.  *----------------------------------------------------------------------
  339.  *
  340.  * CheckFilesystem --
  341.  *
  342.  *    Perform consistency checks on the file system.
  343.  *
  344.  * Results:
  345.  *    An error code, probably from a read.
  346.  *
  347.  * Side effects:
  348.  *    Error flags may be set
  349.  *
  350.  *----------------------------------------------------------------------
  351.  */
  352. void
  353. CheckFilesystem(firstPartFID, partFID, partition)
  354.     int firstPartFID;    /* Handle on the first partition of the disk */
  355.     int partFID;    /* Handle on the partition of the disk to format */
  356.     int partition;    /* Index of parition that is to be dumped */
  357. {
  358.     Disk_Label            *labelPtr;
  359.     FdInfo                *descInfoPtr;
  360.     register    FdInfo          *tDescInfoPtr;
  361.     unsigned char        *tFdBitmapPtr;
  362.     unsigned    char          *newCylBitmapPtr;
  363.     int                i, j, k;
  364.     int                fdNum;
  365.     char            *block;
  366.     Fsdm_FileDescriptor        *fdPtr;
  367.     int                sector;
  368.     unsigned int        validMask;
  369.     int                valid;
  370.     int                salvage;
  371.     unsigned char         *oldPtr;
  372.     unsigned char         *newPtr;
  373.     int                blockNum;
  374.     int                bitmapError = 0;
  375.     RelocListElement        *relocElemPtr;
  376.     CopyListElement        *copyElemPtr;
  377.     Boolean            blockModified;
  378.     Fsdm_FileDescriptor        *fdCopyPtr = NULL;
  379.     Boolean            copyUsed;
  380.     Boolean            batchRead;
  381.     char            *blockBuffer;
  382.     Boolean            blockBufferModified;
  383.     int                numFileDescBlocks;
  384.     Boolean            fdMagicOkay;
  385.     int             status;
  386.  
  387.  
  388.  
  389.     /*
  390.      * Read the copy of the super block at the beginning of the partition
  391.      * to find out basic disk geometry and where to find the domain header.
  392.      */
  393.     labelPtr = Disk_ReadLabel(firstPartFID);
  394.     if (labelPtr == NULL) {
  395.     Output(stderr, "CheckFilesystem: Could not read disk label\n");
  396.     exit(EXIT_READ_FAILURE);
  397.     }
  398.     fflush(stderr);
  399.     fflush(stdout);
  400.     Alloc(blockBuffer, char, blocksToRead * FS_BLOCK_SIZE);
  401.     if (tooBig) {
  402.     Output(stderr,"CheckFileSystem: Heap limit too small.\n");
  403.     exit(EXIT_MORE_MEMORY);
  404.     }
  405.     domainPtr = Disk_ReadDomainHeader(partFID, labelPtr);
  406.     if (domainPtr == NULL) {
  407.     Output(stderr, "CheckFilesystem: Could not read domain header\n");
  408.     exit(EXIT_READ_FAILURE);
  409.     }
  410.     /*
  411.      * See if we need to patch the host ID in the domain header.
  412.      */
  413.     if (patchHeader) {
  414.     int        spriteID;
  415.     struct stat    attrs;
  416.  
  417.     if (hostID != 0) {
  418.         spriteID = hostID;
  419.     } else {
  420.         /*
  421.          * Determine where the disk is located so we can set the
  422.          * spriteID in the header correctly.  If the disk device is generic
  423.          * we use our own hostID, otherwise use the hostID specified
  424.          * by the device file.
  425.          */
  426.         fstat(firstPartFID, &attrs);
  427.         if (attrs.st_devServerID == FS_LOCALHOST_ID) {
  428.         Proc_GetHostIDs((int *) NULL, &spriteID);
  429.         } else {
  430.         spriteID = attrs.st_devServerID;
  431.         }
  432.     }
  433.     if (spriteID != domainPtr->device.serverID) {
  434.         if (!silent) {
  435.         Output(stderr, "Setting hostID in disk header to 0x%x\n",
  436.                 spriteID);
  437.         }
  438.         domainPtr->device.serverID = spriteID;
  439.     } else {
  440.         if (!silent) {
  441.         Output(stderr, "Leaving hostID as 0x%x\n",spriteID);
  442.         }
  443.         patchHeader = FALSE;
  444.     }
  445.     } else if (debug) {
  446.     Output(stderr,"HostID read off disk is 0x%x\n",
  447.            domainPtr->device.serverID);
  448.     }
  449.     /*
  450.      * Read in the file descriptor bit map and the cylinder bit map.
  451.      */
  452.     fdBitmapPtr = ReadFileDescBitmap(partFID, domainPtr);
  453.     cylBitmapPtr = ReadBitmap(partFID, domainPtr);
  454.     AllocByte(newCylBitmapPtr,unsigned char,domainPtr->bitmapBlocks * 
  455.     FS_BLOCK_SIZE);
  456.     if (tooBig) {
  457.     Output(stderr,"CheckFileSystem: Heap limit too small.\n");
  458.     exit(EXIT_MORE_MEMORY);
  459.     }
  460.     bzero((Address)newCylBitmapPtr, domainPtr->bitmapBlocks * FS_BLOCK_SIZE); 
  461.     /*
  462.      * Allocate the descriptor info array.
  463.      */
  464.     Alloc(descInfoPtr,FdInfo,domainPtr->numFileDesc);
  465.     if (tooBig) {
  466.     Output(stderr,"CheckFileSystem: Heap limit too small.\n");
  467.     exit(EXIT_MORE_MEMORY);
  468.     }
  469.     bzero((Address)descInfoPtr, domainPtr->numFileDesc * sizeof(FdInfo));
  470.  
  471.     num1KBlocks = domainPtr->dataCylinders * 
  472.           domainPtr->geometry.blocksPerCylinder * FS_FRAGMENTS_PER_BLOCK;
  473.     bytesPerCylinder = (domainPtr->geometry.blocksPerCylinder + 1) / 2;
  474.     List_Init(modList);
  475.     List_Init(relocList);
  476.     List_Init(copyList);
  477.  
  478.     /*
  479.      * Check the disk to see if the disk has been checked already.
  480.      */
  481.     if (verbose) {
  482.         Output(stderr, "Performing recovery check\n");
  483.     }
  484.     status = RecoveryCheck(partFID, labelPtr);
  485.     if (dontRecheck && status) {
  486.     if (!silent) {
  487.         Output(stderr, 
  488.     "Disk is marked as just checked. I won't bother checking it again.\n");
  489.     }
  490.     FindOutputFile();
  491.     return;
  492.     }
  493.     /*
  494.      * Recreate the file descriptor bit map and check the block counts and 
  495.      * make sure that all blocks are referenced.  Also recreate the data block
  496.      * bitmap.
  497.      */
  498.     if (verbose) {
  499.     Output(stderr, "Checking file descriptors:\n");
  500.     }
  501.  
  502.     tDescInfoPtr = descInfoPtr;
  503.     tFdBitmapPtr = fdBitmapPtr;
  504.     fdNum = 0;
  505.     numFileDescBlocks = (domainPtr->numFileDesc + FSDM_FILE_DESC_PER_BLOCK - 1) / 
  506.         FSDM_FILE_DESC_PER_BLOCK;
  507.     if (blocksToRead > numFileDescBlocks) {
  508.     blocksToRead = numFileDescBlocks;
  509.     }
  510.     for (i = 0; 
  511.      (i < numFileDescBlocks) && !tooBig;
  512.     i += blocksToRead) {
  513.     batchRead = TRUE;
  514.     if (Disk_BlockRead(partFID, domainPtr, 
  515.                domainPtr->fileDescOffset + i,
  516.                blocksToRead, (Address) blockBuffer) < 0) {
  517.         batchRead = FALSE;
  518.         OutputPerror("CheckFilesystem: read of fd's failed");
  519.     }
  520.     block = blockBuffer;
  521.     blockBufferModified = FALSE;
  522.     for (k = 0; k < blocksToRead; k++) {
  523.         if (batchRead) {
  524.         block = &(blockBuffer[k * FS_BLOCK_SIZE]);
  525.         salvage = 0;
  526.         } else {
  527.         /*
  528.          * We couldn't read all of the disk blocks at once, so try
  529.          * to read them one at a time.
  530.          */
  531.         if (Disk_BlockRead(partFID, domainPtr, 
  532.                    domainPtr->fileDescOffset + i + k,
  533.                    1, (Address) block) < 0) {
  534.             /*
  535.              * Hit a disk error reading the block.  Read it a sector
  536.              * at a time and try to salvage what we can.
  537.              */
  538.             OutputPerror("CheckFilesystem: BlockRead: Read failed");
  539.             validMask = Disk_BadBlockRead(partFID, domainPtr,
  540.                           domainPtr->fileDescOffset + i + k,
  541.                           (Address) block);
  542.             SetBadDescBitmap(domainPtr, fdNum, &tFdBitmapPtr);
  543.             salvage = 1;
  544.         }
  545.         }
  546.         if (!salvage) {
  547.         CheckFDBitmap(domainPtr, fdNum, block, &tFdBitmapPtr);
  548.         valid = 1;
  549.         }
  550.         blockModified = FALSE;
  551.         for (sector = 0; 
  552.              sector < DISK_SECTORS_PER_BLOCK && !tooBig; 
  553.          sector++) {
  554.         if (salvage) {
  555.             valid = (validMask & (1 << sector)) != 0;
  556.             numBadDesc++;
  557.         }
  558.         for (j = 0; 
  559.              j < FILE_DESC_PER_SECTOR && 
  560.              fdNum < domainPtr->numFileDesc && !tooBig;
  561.              j++, fdNum++, tDescInfoPtr++, fdPtr++) {
  562.     
  563.             int    modified = 0;
  564.             fdPtr = (Fsdm_FileDescriptor *)    
  565.                 &block[(j + (FILE_DESC_PER_SECTOR * sector)) *
  566.                 FSDM_MAX_FILE_DESC_SIZE];
  567.              if (fdPtr->magic != FSDM_FD_MAGIC) {
  568.              if (!silent) {
  569.                  Output(stderr, 
  570.      "File %d has an invalid magic number <0x%x> and is being reset.\n",
  571.                     fdNum, fdPtr->magic);
  572.                  Output(stderr,
  573.                  "Current block is %d.\n", 
  574.                  i + k + domainPtr->fileDescOffset);
  575.              }
  576.              UnmarkFDBitmap(fdNum,fdBitmapPtr);
  577.              fdMagicOkay = FALSE;
  578.              } else {
  579.              fdMagicOkay = TRUE;
  580.              }
  581.             /* 
  582.              * Make a copy of the fd to be used by elements in 
  583.              * the lists. We have to do this because we can't keep
  584.              * all of the fd's in memory at once.
  585.              */
  586.             if (fdCopyPtr == NULL) { 
  587.             Alloc(fdCopyPtr,Fsdm_FileDescriptor,1);
  588.             if (tooBig) {
  589.                 continue;
  590.             }
  591.             }
  592.             bcopy((Address)fdPtr, (Address)fdCopyPtr, 
  593.               sizeof(Fsdm_FileDescriptor));
  594.             copyUsed = FALSE;
  595.             relocElemPtr = NULL;
  596.             copyElemPtr = NULL;
  597.             if (salvage) {
  598.             if (valid && fdMagicOkay && 
  599.                 (fdPtr->flags & FSDM_FD_ALLOC)) {
  600.                 /* 
  601.                  * If the descriptor is valid and is in a disk block
  602.                  * that is bad, put the fd on a list for relocation.
  603.                  */
  604.                 Alloc(relocElemPtr,RelocListElement,1);
  605.                 if (tooBig) {
  606.                 continue;
  607.                 }
  608.                 tDescInfoPtr->flags |= FD_RELOCATE;
  609.                 relocElemPtr->origFdNum = fdNum;
  610.                 relocElemPtr->newFdNum = -1;
  611.                 relocElemPtr->fdPtr = fdCopyPtr;
  612.                 copyUsed = TRUE;
  613.             }
  614.             if (!valid) {
  615.                 tDescInfoPtr->flags |= FD_UNREADABLE;
  616.             }
  617.             }
  618.             if (valid && fdMagicOkay) {
  619.             if (fdPtr->fileType == FS_DIRECTORY) {
  620.                 tDescInfoPtr->flags |= IS_A_DIRECTORY;
  621.             }
  622.             if (fdPtr->flags & FSDM_FD_ALLOC) {
  623.                 tDescInfoPtr->flags |= FD_ALLOCATED;
  624.                 tDescInfoPtr->origLinkCount = fdPtr->numLinks;
  625.  
  626.                 CheckBlocks(partFID, domainPtr, fdNum, fdCopyPtr,
  627.                     newCylBitmapPtr, &modified,©Used);
  628.                 if (modified) {
  629.                 blockModified = TRUE;
  630.                 }
  631.                 if (tooBig) {
  632.                 continue;
  633.                 }
  634.             } else if (debug && 
  635.                        fdNum == FSDM_BAD_BLOCK_FILE_NUMBER &&
  636.                    fdPtr->firstByte == -1){
  637.                 Output(stderr,"bad block has been reset.\n");
  638.             }
  639.             }
  640.             if ((badBlockInit && fdNum == FSDM_BAD_BLOCK_FILE_NUMBER) ||
  641.                 (salvage && !valid) || !(fdMagicOkay)) {
  642.             if (badBlockInit && 
  643.                 fdNum == FSDM_BAD_BLOCK_FILE_NUMBER) {
  644.                 Output(stderr,  
  645.                    "Clearing bad block file descriptor.\n");
  646.             }
  647.             ClearFd(fdMagicOkay ? FSDM_FD_ALLOC : FSDM_FD_FREE, 
  648.                 fdCopyPtr);
  649.             blockModified = TRUE;
  650.             modified = 1;
  651.             }
  652.             if (relocElemPtr != NULL) {
  653.                List_Insert((List_Links *)relocElemPtr,
  654.                    LIST_ATREAR(relocList));
  655.             }
  656.             if (modified) {
  657.             bcopy((Address)fdCopyPtr, (Address)fdPtr, 
  658.                   sizeof(Fsdm_FileDescriptor));
  659.                 fdPtr->version++;
  660.             }
  661.             if (copyUsed) {
  662.             fdCopyPtr = NULL;
  663.             }
  664.         }
  665.         }
  666.         if (blockModified) {
  667.         blockBufferModified = TRUE;
  668.         if (!batchRead && writeDisk) {
  669.             if (Disk_BlockWrite(partFID, domainPtr,
  670.                     domainPtr->fileDescOffset + i + k,
  671.                     1, (Address) block) < 0) {
  672.             OutputPerror("CheckFileSystem: FD write failed");
  673.             exit(EXIT_WRITE_FAILURE);
  674.             }
  675.         }
  676.         }
  677.     }
  678.     if (batchRead && blockBufferModified && writeDisk) {
  679.         if (Disk_BlockWrite(partFID, domainPtr,
  680.                 domainPtr->fileDescOffset + i,
  681.                 blocksToRead, (Address) blockBuffer) < 0) {
  682.         OutputPerror("CheckFileSystem: FD write failed");
  683.         exit(EXIT_WRITE_FAILURE);
  684.         }
  685.     }
  686.     }
  687.     if (!silent && fdBitmapError) {
  688.     Output(stderr, "Found error in file descriptor bitmap\n");
  689.     }
  690.  
  691.  
  692.     /*
  693.      * We now know which descriptors, if any, need to be relocated.  Allocate
  694.      * new descriptors to hold the information.
  695.      */
  696.  
  697.     if (!(List_IsEmpty(relocList))) {
  698.     LIST_FORALL(relocList, (List_Links *)relocElemPtr) {
  699.         RelocateFD(domainPtr, descInfoPtr, relocElemPtr);
  700.     }
  701.     }
  702.     /*
  703.      * Fix all blocks that appeared in more than one file.
  704.      */
  705.     if (!(List_IsEmpty(copyList))) {
  706.     int status = 0;
  707.  
  708.     if (verbose) {
  709.         Output(stderr, "\nCopying duplicate blocks\n");
  710.     }
  711.     LIST_FORALL(copyList, (List_Links *)copyElemPtr) {
  712.         List_Remove((List_Links *) copyElemPtr);
  713.         if (status != -1 && !noCopy) {
  714.         status = CopyBlock(domainPtr, descInfoPtr, partFID, 
  715.                    newCylBitmapPtr, copyElemPtr);
  716.         }
  717.         if ((copyElemPtr->parentType == FD) && 
  718.         !((descInfoPtr[copyElemPtr->parentNum].flags & 
  719.          (ON_MOD_LIST | FD_RELOCATE)))) {
  720.          free((Address) copyElemPtr->fdPtr);
  721.         }
  722.         free((Address) copyElemPtr);
  723.     }
  724.     }
  725.     /*
  726.      * Go through the file system starting at the root and perform a 
  727.      * consistency check.
  728.      */
  729.     if (!tooBig) {
  730.     if (verbose) {
  731.         Output(stderr, "Traversing directory tree:\n\n");
  732.     }
  733.     
  734.     CheckDirTree(partFID, domainPtr, descInfoPtr, fdBitmapPtr,
  735.              newCylBitmapPtr);
  736.     } else {
  737.     Output(stderr,
  738.            "NOT traversing directory tree because heap limit exceeded.\n"
  739.            );
  740.     }
  741.     /*
  742.      * Now compare the two data block bitmaps.
  743.      */
  744.     if (verbose) {
  745.     Output(stderr, "Comparing old and new data block bit maps:\n");
  746.     }
  747.     /*
  748.      * Block 0 is reserved for the root directory, so mark it as in use.
  749.      * There is code in the file system that will panic if block 0 is
  750.      * reallocated.
  751.      */
  752.     if ((*cylBitmapPtr & 0xf0) != 0xf0) {
  753.     if (!silent) {
  754.         Output(stderr, "Block 0 is free. Marking it used.\n");
  755.     }
  756.     foundError = 1;
  757.     bitmapError = 1;
  758.     }
  759.     *newCylBitmapPtr |= 0xf0;
  760.     *cylBitmapPtr |= 0xf0;
  761.     for (oldPtr = cylBitmapPtr, newPtr = newCylBitmapPtr, i = 0, blockNum = 0; 
  762.      i < domainPtr->dataCylinders; 
  763.      i++, oldPtr = &cylBitmapPtr[bytesPerCylinder * i], 
  764.           newPtr = &newCylBitmapPtr[bytesPerCylinder * i]) {
  765.     for (j = 0; 
  766.          j < bytesPerCylinder; 
  767.          j++, oldPtr++, newPtr++, blockNum += 2) {
  768.         if ((*oldPtr & 0xf0) != (*newPtr & 0xf0)) {
  769.         if (bitmapVerbose) {
  770.             Output(stderr,"Block %d: old %x new %x.\n",
  771.             blockNum * FS_FRAGMENTS_PER_BLOCK,
  772.             (*oldPtr & 0xf0) >> 4, (*newPtr & 0xf0) >> 4);
  773.         }
  774.         foundError = 1;
  775.         bitmapError = 1;
  776.         } 
  777.         if ((*oldPtr & 0x0f) != (*newPtr & 0x0f)) {
  778.         if (bitmapVerbose) {
  779.             Output(stderr,"Block %d: old %x new %x.\n",
  780.                (blockNum + 1) * FS_FRAGMENTS_PER_BLOCK,
  781.                *oldPtr & 0x0f, *newPtr & 0x0f);
  782.         }
  783.         foundError = 1;
  784.         bitmapError = 1;
  785.         }
  786.     }
  787.     }
  788.     if (!silent && bitmapError) {
  789.     Output(stderr, "Found error in data block bitmap\n");
  790.     }
  791.     fflush(stderr);
  792.  
  793.     /*
  794.      * Print status information about disk.
  795.      */
  796.     Output(stdout, 
  797.         "%d files, %d blocks in use, %d blocks free, %d fragments\n",
  798.         numFiles, numBlocks, domainPtr->dataBlocks * 4 - numBlocks,
  799.         numFrags);
  800.  
  801.  
  802.     if (foundError) {
  803.     fixCount++;
  804.     if (fixCount > numReboot) {
  805.         foundError = 1;
  806.         errorType = EXIT_NOREBOOT;
  807.     }
  808.     } else {
  809.     fixCount = 0;
  810.     }
  811.     if (!writeDisk) {
  812.     return;
  813.     }
  814.  
  815.     if (verbose) {
  816.     Output(stderr, "Writing disk\n");
  817.     }
  818.     fflush(stderr);
  819.  
  820.     /*
  821.      * Write the file descriptor and data block bitmaps back out along with
  822.      * the file descriptors.
  823.      */
  824.     if (patchHeader) {
  825.     status = Disk_WriteDomainHeader(partFID, labelPtr, domainPtr);
  826.     if (status != 0) {
  827.         Output(stderr, "Unable to write domain header.\n");
  828.         exit(EXIT_WRITE_FAILURE);
  829.     }
  830.     }
  831.  
  832.     WriteFileDescBitmap(partFID, domainPtr, fdBitmapPtr);
  833.     WriteBitmap(partFID, domainPtr, newCylBitmapPtr);
  834.  
  835.     /*
  836.      * Write out any modified file descriptors on the modified list.
  837.      */
  838.     WriteFileDesc(partFID, domainPtr, modList, descInfoPtr);
  839.     WriteFileDesc(partFID, domainPtr, relocList, descInfoPtr);
  840.     WriteSummaryInfo(partFID, labelPtr, domainPtr, 
  841.                 numBlocks, numFiles);
  842. }
  843.  
  844.  
  845. /*
  846.  *----------------------------------------------------------------------
  847.  *
  848.  * CheckBlocks --
  849.  *
  850.  *    Check all the blocks associated with a file descriptor.
  851.  *
  852.  *
  853.  * Results:
  854.  *    None.
  855.  *
  856.  * Side effects:
  857.  *    Error flags may be set.
  858.  *
  859.  *----------------------------------------------------------------------
  860.  */
  861. void
  862. CheckBlocks(partFID, domainPtr, fdNum, fdPtr, newCylBitmapPtr, modifiedPtr,
  863.         copyUsedPtr)
  864.     int         partFID;        /* Raw handle on disk. */
  865.     Ofs_DomainHeader    *domainPtr;        /* Ptr to domain info. */
  866.     int            fdNum;            /* File descriptor # to check.*/
  867.     Fsdm_FileDescriptor    *fdPtr;            /* Ptr to file descriptor that
  868.                          * are checking. */
  869.     unsigned char     *newCylBitmapPtr;    /* Pointer to the disk block
  870.                          * bit map. */
  871.     int            *modifiedPtr;        /* TRUE => modified the file */
  872.     Boolean        *copyUsedPtr;        /* TRUE => copy of fd was stored                          * somewhere. */
  873.  {
  874.     register int        *indexPtr;
  875.     register int        i, j;
  876.     static int             *dblIndirectBlock[FSDM_INDICES_PER_BLOCK];
  877.     int                indBlock;
  878.     int                lastBlock;
  879.     int                lastFrag;
  880.     int                tBlock;
  881.     int                dirty;
  882.     int                lastRealBlock;
  883.     int                blockCount = 0;
  884.     int                status = 0;
  885.     Boolean            duplicate;
  886.     int                virtualIndex;
  887.  
  888.     if (!(fdPtr->flags & FSDM_FD_ALLOC)) {
  889.     return;
  890.     }
  891.     numFiles++;
  892.     lastRealBlock = -1;
  893.     /*
  894.      * -1 is an empty file, anything less is an error.
  895.      */
  896.     if (fdPtr->lastByte < -1) {
  897.     if (verbose || lastErrorFD != fdNum) {
  898.         Output(stderr, "File %d has bogus size %d. Setting to -1.\n",
  899.             fdNum, fdPtr->lastByte);
  900.     }
  901.     fdPtr->lastByte = -1;
  902.     foundError = 1;
  903.     *modifiedPtr = 1;
  904.     }
  905.     if (fdPtr->lastByte == -1) {
  906.     lastBlock = -1;
  907.     lastFrag = FS_FRAGMENTS_PER_BLOCK - 1;
  908.     } else {
  909.     lastBlock = fdPtr->lastByte / FS_BLOCK_SIZE;
  910.     if (lastBlock < FSDM_NUM_DIRECT_BLOCKS) {
  911.         lastFrag = (fdPtr->lastByte & FS_BLOCK_OFFSET_MASK) / FS_FRAGMENT_SIZE;
  912.     } else {
  913.         lastFrag = FS_FRAGMENTS_PER_BLOCK - 1;
  914.     }
  915.     }
  916.  
  917.     /*
  918.      * First check direct blocks. Loop through them first and see if the 
  919.      * file size corresponds to the number of blocks.
  920.      */
  921.     for (i = 0; i < FSDM_NUM_DIRECT_BLOCKS; i++) {
  922.     if (i > lastBlock && fdPtr->direct[i] != FSDM_NIL_INDEX) {
  923.         lastBlock++;
  924.         fdPtr->lastByte += FS_BLOCK_SIZE;
  925.         foundError = 1;
  926.         *modifiedPtr = 1;
  927.         if (lastFrag != FS_FRAGMENTS_PER_BLOCK - 1) {
  928.         fdPtr->lastByte += (FS_FRAGMENTS_PER_BLOCK -1 - lastFrag) *
  929.                    FS_FRAGMENT_SIZE;
  930.         lastFrag = FS_FRAGMENTS_PER_BLOCK - 1;
  931.         }
  932.         if (verbose || lastErrorFD != fdNum) {
  933.         Output(stderr,
  934.     "Found a direct block beyond end of file %d. Increasing file size.\n",
  935.             fdNum);
  936.         lastErrorFD = fdNum;
  937.         }
  938.     }
  939.     }
  940.     for (i = 0; i < FSDM_NUM_DIRECT_BLOCKS; i++) {
  941.     if (fileToPrint == fdNum) {
  942.         Output(stderr, "File %d, d[%d] = %d.\n", fdNum, i, 
  943.         fdPtr->direct[i]);
  944.     }
  945.     if (fdPtr->direct[i] != FSDM_NIL_INDEX) {
  946.         if (blockToFind == fdPtr->direct[i]) {
  947.         Output(stderr, "Block %d is d[%d] in file %d.\n", 
  948.             fdPtr->direct[i], i, fdNum);
  949.         }
  950.         if (i == lastBlock) {
  951.         status = MarkBitmap(fdNum, fdPtr->direct[i],
  952.                     newCylBitmapPtr,
  953.                     lastFrag + 1, domainPtr);
  954.         if (status >= 0) {
  955.             if (lastFrag + 1 != FS_FRAGMENTS_PER_BLOCK) {
  956.             numFrags++;
  957.             }
  958.             blockCount += lastFrag + 1;
  959.             numBlocks += lastFrag + 1;
  960.         }
  961.         } else {
  962.         if (fdPtr->direct[i] & 
  963.             (FS_FRAGMENTS_PER_BLOCK - 1)) {
  964.             if (verbose || lastErrorFD != fdNum) {
  965.             Output(stderr,
  966.   "Block pointer %d invalid  in direct block %d of file %d. Block deleted.\n",
  967.                     fdPtr->direct[i],i,fdNum);
  968.             lastErrorFD = fdNum;
  969.             }
  970.             foundError = 1;
  971.             status = -1;
  972.         } else {
  973.             status = MarkBitmap(fdNum, fdPtr->direct[i],
  974.                     newCylBitmapPtr,
  975.                     FS_FRAGMENTS_PER_BLOCK, domainPtr);
  976.             if (status >= 0) {
  977.             blockCount += FS_FRAGMENTS_PER_BLOCK;
  978.             numBlocks += FS_FRAGMENTS_PER_BLOCK;
  979.             }
  980.         }
  981.         }
  982.         /*
  983.          * Current block is also used by another file. Put info in copy
  984.          * list so block is copied.
  985.          */
  986.         if (status == 1) {
  987.         if (!tooBig) {
  988.             AddToCopyList(FD,fdPtr,fdNum,0,i,DIRECT, 
  989.                   (i == lastBlock) ? lastFrag + 1 :
  990.                       FS_FRAGMENTS_PER_BLOCK,  copyUsedPtr);
  991.         }
  992.         }
  993.         if (status < 0) {
  994.         fdPtr->direct[i] = FSDM_NIL_INDEX;
  995.         if (fdPtr->fileType == FS_DIRECTORY) {
  996.             if (verbose || lastErrorFD != fdNum) {
  997.             Output(stderr,
  998.             "Hole in directory %d at direct block %d.\n", fdNum,
  999.             i);
  1000.             lastErrorFD = fdNum;
  1001.             }
  1002.             AddToCopyList(FD,fdPtr,fdNum,0,i,DIRECT, 
  1003.                   (i == lastBlock) ? lastFrag + 1 :
  1004.                   FS_FRAGMENTS_PER_BLOCK,  copyUsedPtr);
  1005.         }
  1006.         } else {
  1007.         lastRealBlock = i;
  1008.         if (i == lastBlock) {
  1009.             break;
  1010.         }
  1011.         }
  1012.     } else if (fdPtr->fileType == FS_DIRECTORY) {
  1013.         if (verbose || lastErrorFD != fdNum) {
  1014.         Output(stderr, "Hole in directory %d at direct block %d.\n", 
  1015.         fdNum, i);
  1016.         lastErrorFD = fdNum;
  1017.         }
  1018.         AddToCopyList(FD,fdPtr,fdNum,0,i,DIRECT, 
  1019.               (i == lastBlock) ? lastFrag + 1 :
  1020.               FS_FRAGMENTS_PER_BLOCK,  copyUsedPtr);
  1021.     }
  1022.     }
  1023.     /*
  1024.      * Now check the singly indirect block.
  1025.      */
  1026.     if (fdPtr->indirect[0] == FSDM_NIL_INDEX) {
  1027.     if (fdPtr->fileType == FS_DIRECTORY && 
  1028.         lastBlock > FSDM_NUM_DIRECT_BLOCKS) {
  1029.         if (verbose || lastErrorFD != fdNum) {
  1030.         Output(stderr,
  1031.         "Hole in directory %d at single indirect block\n",
  1032.                    fdNum);
  1033.         lastErrorFD = fdNum;
  1034.         }
  1035.         AddToCopyList(FD,fdPtr,fdNum,0,FSDM_NUM_DIRECT_BLOCKS,INDIRECT, 
  1036.               FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1037.     }
  1038.     i += FSDM_INDICES_PER_BLOCK;
  1039.     } else {
  1040.     tBlock = i;
  1041.     status = ProcessIndirectBlock(fdNum, partFID,lastBlock, FALSE, fdPtr, 
  1042.                       &fdPtr->indirect[0], newCylBitmapPtr,
  1043.                       domainPtr,&tBlock, &dirty,
  1044.                       &lastRealBlock, modifiedPtr, &blockCount,
  1045.                       copyUsedPtr);
  1046.     i = tBlock;
  1047.     /*
  1048.      * We need to copy block
  1049.      */
  1050.     if (status == 1) {
  1051.         AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS, INDIRECT,
  1052.               FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1053.     }  
  1054.     if (status < 0) {
  1055.         if (verbose || lastErrorFD != fdNum) {
  1056.         Output(stderr, 
  1057.                 "Hole in directory %d at single indirect block\n",
  1058.                    fdNum);
  1059.         lastErrorFD = fdNum;
  1060.         }
  1061.         AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS, INDIRECT,
  1062.               FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1063.     } 
  1064.     }
  1065.     if (fdPtr->indirect[1] == FSDM_NIL_INDEX) {
  1066.     goto checkBlockCount;
  1067.     }
  1068.  
  1069.     /*
  1070.      * Now check doubly indirect blocks.
  1071.      */
  1072.     indBlock = fdPtr->indirect[1];
  1073.     if (indBlock & (FS_FRAGMENTS_PER_BLOCK - 1)) {
  1074.     if (verbose || lastErrorFD != fdNum) {
  1075.         Output(stderr, 
  1076.  "Doubly indirect block %d on non-block boundary in file %d.  Block deleted.\n",
  1077.               indBlock, fdNum);
  1078.         lastErrorFD = fdNum;
  1079.         setCheckedBit = FALSE;
  1080.     }
  1081.     foundError = 1;
  1082.     status = -1;
  1083.     } else {
  1084.     status = MarkBitmap(fdNum, PhysToVirt(domainPtr, indBlock),
  1085.         newCylBitmapPtr,
  1086.         FS_FRAGMENTS_PER_BLOCK, domainPtr);
  1087.     }
  1088.     if (status >= 0) {
  1089.     if (Disk_BlockRead(partFID, domainPtr, 
  1090.                indBlock / FS_FRAGMENTS_PER_BLOCK,
  1091.                1, (Address) dblIndirectBlock) < 0) {
  1092.         OutputPerror("CheckBlocks: Read failed");
  1093.         fdPtr->indirect[1] = FSDM_NIL_INDEX;
  1094.         *modifiedPtr = 1;
  1095.         goto truncFile;
  1096.     }
  1097.     /* 
  1098.      * Look over contents of block first and see if they make sense.
  1099.      */
  1100.     for (j = 0, indexPtr = (int *) dblIndirectBlock; 
  1101.          j < FSDM_INDICES_PER_BLOCK; 
  1102.          j++, indexPtr++) {
  1103.         if (*indexPtr != FSDM_NIL_INDEX) {
  1104.         virtualIndex = PhysToVirt(domainPtr, *indexPtr);
  1105.         if (virtualIndex < 0 || virtualIndex >= num1KBlocks) {
  1106.             if (verbose || lastErrorFD != fdNum) {
  1107.             Output(stderr, 
  1108.             "Double indirect block %d of file %d contains garbage index %d\n", 
  1109.                        indBlock, fdNum, *indexPtr);
  1110.             lastErrorFD = fdNum;
  1111.             }
  1112.             fdPtr->indirect[1] = FSDM_NIL_INDEX;
  1113.             setCheckedBit = FALSE;
  1114.             *modifiedPtr = 1;
  1115.             goto truncFile;
  1116.         } else if ( i + j * FSDM_INDICES_PER_BLOCK > lastBlock) {
  1117.             lastBlock = i + j * FSDM_INDICES_PER_BLOCK;
  1118.             fdPtr->lastByte += FS_BLOCK_SIZE * FSDM_INDICES_PER_BLOCK;
  1119.             *modifiedPtr = 1;
  1120.         }
  1121.  
  1122.         }
  1123.     }
  1124.     duplicate = FALSE;
  1125.     if (status == 1) {
  1126.         duplicate = TRUE;
  1127.         AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
  1128.               DBL_INDIRECT,    FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1129.     }
  1130.     for (j = 0, indexPtr = (int *) dblIndirectBlock; 
  1131.          j < FSDM_INDICES_PER_BLOCK && i <= lastBlock; 
  1132.          j++, indexPtr++) {
  1133.         if (*indexPtr == FSDM_NIL_INDEX) {
  1134.         if (fdPtr->fileType == FS_DIRECTORY) {
  1135.             if (verbose || lastErrorFD != fdNum) {
  1136.             Output(stderr, 
  1137.             "Hole in directory %d in doubly indirect block\n",
  1138.                        fdNum);
  1139.             lastErrorFD = fdNum;
  1140.             }
  1141.             AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
  1142.               DBL_INDIRECT, FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1143.         }
  1144.         i += FSDM_INDICES_PER_BLOCK;
  1145.         continue;
  1146.         }
  1147.         tBlock = i;
  1148.         status = ProcessIndirectBlock(fdNum, partFID, lastBlock, duplicate, 
  1149.                       fdPtr, indexPtr, newCylBitmapPtr,
  1150.                       domainPtr, &tBlock, &dirty,
  1151.                       &lastRealBlock, modifiedPtr, 
  1152.                       &blockCount, copyUsedPtr);
  1153.        i = tBlock;
  1154.        if (status < 0) {
  1155.         if (verbose || lastErrorFD != fdNum) {
  1156.             Output(stderr, 
  1157.             "Hole in directory %d in doubly indirect blocks (2)\n",
  1158.                        fdNum);
  1159.             lastErrorFD = fdNum;
  1160.         }
  1161.         AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
  1162.               DBL_INDIRECT, FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1163.         }
  1164.     }
  1165.     if (status == 1 && !duplicate) {
  1166.         AddToCopyList(BLOCK, fdPtr, 0, indBlock, j, INDIRECT, 
  1167.               FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1168.     }
  1169.     if (dirty) {
  1170.         if (writeDisk) {
  1171.         if (Disk_BlockWrite(partFID, domainPtr, 
  1172.                indBlock / FS_FRAGMENTS_PER_BLOCK,
  1173.                1, (Address) dblIndirectBlock) < 0) {
  1174.             OutputPerror("CheckBlocks: Write failed");
  1175.             exit(EXIT_WRITE_FAILURE);
  1176.         }
  1177.         }
  1178.     }
  1179.     numBlocks += FS_FRAGMENTS_PER_BLOCK;
  1180.     blockCount += FS_FRAGMENTS_PER_BLOCK;
  1181.  
  1182.     } else {
  1183.     if (fdPtr->fileType == FS_DIRECTORY) {
  1184.         AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
  1185.               DBL_INDIRECT, FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1186.         } else {
  1187.         fdPtr->indirect[1] = FSDM_NIL_INDEX;
  1188.         *modifiedPtr = 1;
  1189.     }
  1190.     }
  1191.  
  1192.     if (lastRealBlock == lastBlock) {
  1193.     goto checkBlockCount;
  1194.     }
  1195.  
  1196. truncFile:
  1197.  
  1198.     if (lastRealBlock != -1) {
  1199.     fdPtr->lastByte = (lastRealBlock + 1) * FS_BLOCK_SIZE - 1;
  1200.     } else {
  1201.     fdPtr->lastByte = -1;
  1202.     }
  1203.     Output(stderr,"Truncating file %d to length %d\n", fdNum,
  1204.                  fdPtr->lastByte + 1);
  1205.     foundError = 1;
  1206.     *modifiedPtr = 1;
  1207.  
  1208. checkBlockCount:
  1209.  
  1210.     if (blockCount != fdPtr->numKbytes) {
  1211.     if (verbose || lastErrorFD != fdNum) {
  1212.         Output(stderr,
  1213.         "Block count corrected for file %d.  Is %d should be %d.\n", 
  1214.                fdNum, fdPtr->numKbytes, blockCount);
  1215.         lastErrorFD = fdNum;
  1216.     }
  1217.     fdPtr->numKbytes = blockCount;
  1218.     foundError = 1;
  1219.     *modifiedPtr = 1;
  1220.     }
  1221. }
  1222.  
  1223. /*
  1224.  *----------------------------------------------------------------------
  1225.  *
  1226.  * ProcessIndirectBlock --
  1227.  *
  1228.  *    Scan through the file descriptors in the indirect block and
  1229.  *    update the cylinder map to reflect which blocks are allocated.
  1230.  *
  1231.  * Results:
  1232.  *    -1 if found a hole in an indirect block for a directory
  1233.  *    1 if block is already in use
  1234.  *    0 otherwise.
  1235.  *
  1236.  * Side effects:
  1237.  *    None.
  1238.  *
  1239.  *----------------------------------------------------------------------
  1240.  */
  1241. int
  1242. ProcessIndirectBlock(fdNum, partFID,lastBlock,duplicate, fdPtr, blockNumPtr, 
  1243.              newCylBitmapPtr,domainPtr,fileBlockNumPtr, dirtyPtr,
  1244.              lastRealBlockPtr, modifiedPtr, blockCountPtr,
  1245.              copyUsedPtr)
  1246.     int            fdNum;          /* Number of file descriptor that 
  1247.                          indirect block is in. */
  1248.     register Fsdm_FileDescriptor    *fdPtr;      /* Actual file descriptor. */
  1249.     int            *blockNumPtr;      /* Pointer to indirect block number */
  1250.     unsigned    char     *newCylBitmapPtr; /* The cylinder bit map to set bits
  1251.                          in for allocated blocks. */
  1252.     int            partFID;      /* File id to use to read in indirect
  1253.                          blocks from disk. */
  1254.     Ofs_DomainHeader    *domainPtr;      /* Domain to read from. */
  1255.     int            lastBlock;      /* The last block in the file. */
  1256.     int            *fileBlockNumPtr; /* Pointer to file block number. */
  1257.     int            *dirtyPtr;      /* 1 if *blockNumPtr gets 
  1258.                          modified. */
  1259.     int            *lastRealBlockPtr; /* Pointer to the number of the last
  1260.                           valid block that was found for the
  1261.                           file. */
  1262.     int            *modifiedPtr;       /* 1 if the file descriptor
  1263.                           is modified. */
  1264.     int            *blockCountPtr;       /* Count of the number of blocks in
  1265.                         * the file. */
  1266.     Boolean        *copyUsedPtr;       /* TRUE => copy of fd was stored
  1267.                         * somewhere and should not be
  1268.                         * reused. */
  1269.     Boolean        duplicate;       /* TRUE => we are processing a 
  1270.                         * duplicate block, therefore all
  1271.                         * direct blocks will also be 
  1272.                         * duplicates. */
  1273. {
  1274.     static char        indirectBlock[FS_BLOCK_SIZE];
  1275.     int            *indexPtr;
  1276.     int            i;
  1277.     int            dirty = 0;
  1278.     int            status;
  1279.     int         tempFileBlock;
  1280.     Boolean        foundDuplicate = FALSE;
  1281.     int            zeroCount;
  1282.  
  1283.  
  1284.  
  1285.     if (*blockNumPtr & (FS_FRAGMENTS_PER_BLOCK - 1)) {
  1286.     if (verbose || lastErrorFD != fdNum) {
  1287.         Output(stderr, 
  1288.     "Indirect block on a non-block boundary for file %d.  Block deleted.\n",
  1289.                fdNum);
  1290.         lastErrorFD = fdNum;
  1291.     }
  1292.     foundError = 1;
  1293.     status = -1;
  1294.     } else {
  1295.     status = MarkBitmap(fdNum, PhysToVirt(domainPtr, *blockNumPtr), 
  1296.                 newCylBitmapPtr, 
  1297.                 FS_FRAGMENTS_PER_BLOCK, domainPtr);
  1298.     }
  1299.     if (status == 0) {
  1300.         /*
  1301.          * FIXME: need to be able to flag this as a bad block on error.
  1302.          */
  1303.     status = Disk_BlockRead(partFID, domainPtr, 
  1304.                        *blockNumPtr / FS_FRAGMENTS_PER_BLOCK, 1, 
  1305.                    (Address) indirectBlock);
  1306.     if (status < 0) {
  1307.         OutputPerror("ProcessIndirectBlock: Read failed");
  1308.     }
  1309.     } else if (status == 1 ) {
  1310.     foundDuplicate = TRUE;
  1311.     }
  1312.     if (status < 0) {
  1313.     if (verbose || lastErrorFD != fdNum) {
  1314.         Output(stderr,
  1315.         "Indirect block (%d) unreadable for file #%d.  Block deleted.\n", 
  1316.                *blockNumPtr, fdNum);
  1317.         lastErrorFD = fdNum;
  1318.     }
  1319.     *fileBlockNumPtr += FSDM_INDICES_PER_BLOCK;
  1320.     *blockNumPtr = FSDM_NIL_INDEX;
  1321.     *dirtyPtr = 1;
  1322.     *modifiedPtr = 1;
  1323.     setCheckedBit = FALSE;
  1324.     return(0);
  1325.     } else {
  1326.     *dirtyPtr = 0;
  1327.     }
  1328.     /* 
  1329.      * Look over contents of block first and see if they make sense.
  1330.      */
  1331.     zeroCount = 0;
  1332.     for (i = 0, indexPtr = (int *) indirectBlock,
  1333.      tempFileBlock = *fileBlockNumPtr; 
  1334.      i < FSDM_INDICES_PER_BLOCK; 
  1335.      i++, tempFileBlock++, indexPtr++) {
  1336.     if (*indexPtr != FSDM_NIL_INDEX) {
  1337.         if (*indexPtr == 0) {
  1338.         zeroCount++;
  1339.         continue;
  1340.         }
  1341.         if (*indexPtr == blockToFind) {
  1342.         Output(stderr, "Block %d is i[%d] in file %d.\n",
  1343.             *indexPtr, i, fdNum);
  1344.         }
  1345.         if (*indexPtr < 0 || *indexPtr >= num1KBlocks) {
  1346.         if (verbose || lastErrorFD != fdNum) {
  1347.             Output(stderr, 
  1348.             "Indirect block %d of file %d contains garbage index %d\n", 
  1349.                    *blockNumPtr, fdNum, *indexPtr);
  1350.             lastErrorFD = fdNum;
  1351.             setCheckedBit = FALSE;
  1352.         }
  1353.             *fileBlockNumPtr += FSDM_INDICES_PER_BLOCK;
  1354.             *blockNumPtr = FSDM_NIL_INDEX;
  1355.             *dirtyPtr = 1;
  1356.             *modifiedPtr = 1;
  1357.             foundError = 1;
  1358.         if (fdPtr->fileType == FS_DIRECTORY) {
  1359.            return(-1);
  1360.         } else {
  1361.            return(0);
  1362.             }
  1363.          } else if (tempFileBlock > lastBlock) {
  1364.          lastBlock = tempFileBlock;
  1365.          fdPtr->lastByte = tempFileBlock * FS_BLOCK_SIZE -1;
  1366.          *modifiedPtr = 1;
  1367.          }
  1368.      }
  1369.      }
  1370.     if (zeroCount == FSDM_INDICES_PER_BLOCK) {
  1371.     if (verbose || lastErrorFD != fdNum) {
  1372.         Output(stderr, "Indirect block %d is all zeros.\n", 
  1373.                *blockNumPtr, *indexPtr);
  1374.         lastErrorFD = fdNum;
  1375.     }
  1376.     *fileBlockNumPtr += FSDM_INDICES_PER_BLOCK;
  1377.     *blockNumPtr = FSDM_NIL_INDEX;
  1378.     *dirtyPtr = 1;
  1379.     *modifiedPtr = 1;
  1380.     foundError = 1;
  1381.     setCheckedBit = FALSE;
  1382.     if (fdPtr->fileType == FS_DIRECTORY) {
  1383.        return(-1);
  1384.     } else {
  1385.        return(0);
  1386.     }
  1387.     }
  1388.     numBlocks += FS_FRAGMENTS_PER_BLOCK;
  1389.     *blockCountPtr += FS_FRAGMENTS_PER_BLOCK;
  1390.      for (i = 0, indexPtr = (int *) indirectBlock; 
  1391.      i < FSDM_INDICES_PER_BLOCK && *fileBlockNumPtr <= lastBlock; 
  1392.      i++, (*fileBlockNumPtr)++, indexPtr++) {
  1393.  
  1394.      if (*indexPtr == FSDM_NIL_INDEX) {
  1395.         if (fdPtr->fileType == FS_DIRECTORY) {
  1396.         AddToCopyList(BLOCK, fdPtr, 0, 
  1397.                 *blockNumPtr, i, DIRECT, 
  1398.                  FS_FRAGMENTS_PER_BLOCK, 
  1399.                  copyUsedPtr);
  1400.         }
  1401.         continue;
  1402.      }
  1403.      if (*indexPtr & (FS_FRAGMENTS_PER_BLOCK - 1)) {
  1404.          if (verbose || lastErrorFD != fdNum) {
  1405.          Output(stderr, 
  1406.          "Non-direct block fragmented for file %d.  Block deleted.\n",
  1407.                fdNum);